package com.deductive.service.dynamic.impl;

import cn.hutool.core.util.StrUtil;
import com.deductive.common.utils.GeometryUtils;
import com.deductive.common.utils.NamingUtils;
import com.deductive.mapper.dynamic.DynamicTableMapper;
import com.deductive.service.dynamic.IDynamicTableService;
import org.locationtech.jts.geom.Geometry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 动态表通用服务实现 (支持命名自动转换和空间数据处理)
 */
@Service
public class DynamicTableServiceImpl implements IDynamicTableService {

    @Autowired
    private DynamicTableMapper dynamicTableMapper;



    @Override
    public List<Map<String, Object>> selectPage(String tableName, List<String> columns, List<Map<String, Object>> conditions) {
        Assert.hasText(tableName, "表名不能为空");

        List<Map<String, Object>> snakeCaseConditions = NamingUtils.conditionsToSnakeCase(conditions);
        List<String> snakeCaseColumns = (columns == null) ? null : columns.stream().map(StrUtil::toUnderlineCase).collect(Collectors.toList());

        handleSpatialConditions(snakeCaseConditions);

        List<Map<String, Object>> listFromDb = dynamicTableMapper.selectPage(tableName, snakeCaseColumns, snakeCaseConditions);

        handleSpatialResults(listFromDb);

        List<Map<String, Object>> camelCaseList = NamingUtils.listToCamelCase(listFromDb);

        return camelCaseList;
    }

    @Override
    @Transactional
    public int insert(String tableName, Map<String, Object> data) {
        Assert.hasText(tableName, "表名不能为空");
        Assert.notEmpty(data, "插入的数据不能为空");
        Map<String, Object> snakeCaseData = NamingUtils.mapToSnakeCase(data);
        int result = dynamicTableMapper.insert(tableName, snakeCaseData);

        if (result > 0) {
            pushTableUpdateNotification(tableName, "INSERT", data);
        }

        return result;
    }

    @Override
    @Transactional
    public int update(String tableName, Map<String, Object> data, List<Map<String, Object>> conditions) {
        Assert.hasText(tableName, "表名不能为空");
        Assert.notEmpty(data, "更新的数据不能为空");
        Assert.isTrue(conditions != null && !conditions.isEmpty(), "更新条件不能为空，以防止全表更新");

        Map<String, Object> snakeCaseData = NamingUtils.mapToSnakeCase(data);
        List<Map<String, Object>> snakeCaseConditions = NamingUtils.conditionsToSnakeCase(conditions);
        handleSpatialConditions(snakeCaseConditions);
        int result = dynamicTableMapper.update(tableName, snakeCaseData, snakeCaseConditions);

        if (result > 0) {
            pushTableUpdateNotification(tableName, "UPDATE", data);
        }

        return result;
    }

    @Override
    @Transactional
    public int delete(String tableName, List<Map<String, Object>> conditions) {
        Assert.hasText(tableName, "表名不能为空");
        Assert.isTrue(conditions != null && !conditions.isEmpty(), "删除条件不能为空，以防止全表删除");

        List<Map<String, Object>> snakeCaseConditions = NamingUtils.conditionsToSnakeCase(conditions);
        handleSpatialConditions(snakeCaseConditions);
        int result = dynamicTableMapper.delete(tableName, snakeCaseConditions);

        if (result > 0) {
            pushTableUpdateNotification(tableName, "DELETE", null);
        }

        return result;
    }

    private void pushTableUpdateNotification(String tableName, String operation, Map<String, Object> data) {
        Map<String, Object> payload = new HashMap<>();
        payload.put("tableName", tableName);
        payload.put("operation", operation);
        payload.put("data", data);

        Map<String, Object> message = new HashMap<>();
        message.put("type", "TABLE_UPDATE");
        message.put("payload", payload);

    }

    @SuppressWarnings("unchecked")
    private void handleSpatialConditions(List<Map<String, Object>> conditions) {
        if (conditions == null) return;
        for (Map<String, Object> condition : conditions) {
            Object operator = condition.get("operator");
            if (operator != null && "intersects".equalsIgnoreCase(operator.toString())) {
                Object value = condition.get("value");
                if (value instanceof Map) {
                    String wkt = GeometryUtils.geoJsonMapToWkt((Map<String, Object>) value);
                    condition.put("value", wkt);
                }
            }
        }
    }

    private void handleSpatialResults(List<Map<String, Object>> results) {
        if (results == null) return;
        for (Map<String, Object> row : results) {
            if (row.containsKey("geom") && row.get("geom") instanceof String) {
                String wkbHex = (String) row.get("geom");
                Geometry geometry = GeometryUtils.wkbHexToGeometry(wkbHex);
                Map<String, Object> geoJsonMap = GeometryUtils.geometryToGeoJsonMap(geometry);
                row.put("geom", geoJsonMap);
            }
        }
    }
}